﻿#include "FITKAbaqusHDF5AdaptorInteraction.h"
#include "FITK_Kernel/FITKCore/FITKEnumTransformer.hpp"

#include "FITK_Interface/FITKInterfaceIO/FITKAbstractHDF5Reader.h"
#include "FITK_Interface/FITKInterfaceIO/FITKAbstractHDF5Writer.h"

#include "FITK_Interface/FITKInterfaceStructural/FITKAbaAbstractInteraction.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaInteractionGeneralContactExplicit.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaInteractionSurfToSurfExplicit.h"

#include "FITK_Component/FITKAbaqusData/FITKDataCase.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaStepManager.h"
#include "FITK_Interface/FITKInterfacePhysics/FITKBoundaryLocation.h"

#include <QDebug>
namespace IO
{
    QString FITKAbaqusHDF5AdaptorInteraction::getAdaptorClass()
    {
        return "FITKAbaqusHDF5AbaqusAdaptorInteraction";
    }

    void FITKAbaqusHDF5AdaptorInteraction::setDataCase(AbaqusData::FITKDataCase* caseData)
    {
        _caseData = caseData;
    }

    bool FITKAbaqusHDF5AdaptorInteraction::adaptR()
    {
        auto interaction = dynamic_cast<Interface::FITKAbaAbstractInteraction*>(_dataObj);
        if (!_reader || !_h5Group || !interaction || !_caseData) return false;
        bool isR = true;
        isR &= readInteraction(interaction, *_h5Group);
        return isR;
    }

    bool FITKAbaqusHDF5AdaptorInteraction::adaptW()
    {
        auto interaction = dynamic_cast<Interface::FITKAbaAbstractInteraction*>(_dataObj);
        if (!_writer || !_h5Group || !interaction || !_caseData) return false;
        bool isW = true;
        isW &= writeInteraction(interaction, *_h5Group);
        return isW;
    }

    bool FITKAbaqusHDF5AdaptorInteraction::readInteraction(Interface::FITKAbaAbstractInteraction * interaction, H5::Group & h5Group)
    {
        if (!interaction) return false;
        bool isR = true;
        isR &= readNDataObject(interaction, h5Group);

        auto firstLocationGroup = h5Group.openGroup("FirstLocation");
        readBoundaryLocation(interaction->getFirstLocation(), firstLocationGroup);
        auto secondLocationGroup = h5Group.openGroup("SecondLocation");
        readBoundaryLocation(interaction->getSecondLocation(), secondLocationGroup);

        if (!h5Group.attrExists("ActiveState")) return false;
        bool ActiveState = readBoolAttribute(h5Group, "ActiveState");
        interaction->setActiveState(ActiveState);

        auto stepManager = _caseData->getStepManager();
        if (!stepManager) return false;

        for (int i = 0; i < stepManager->getDataCount(); ++i)
        {
            auto step = stepManager->getDataByIndex(i);
            int stepID = step->getDataObjectID();
            if (!h5Group.nameExists(std::to_string(stepID))) return false;
            auto stepGroup = h5Group.openGroup(std::to_string(stepID));

            //FITKAbaStepRelatedDataObject
            int CreatedStep = readIntAttribute(stepGroup, "CreatedStep");
            interaction->setCreatedStep(CreatedStep);
            int DeactiveStep = readIntAttribute(stepGroup, "DeactiveStep");
            interaction->setDeactiveStep(DeactiveStep);

            auto InteractionType = interaction->getInteractionType();
            if (InteractionType == Interface::FITKAbaAbstractInteraction::FITKAbaInteractionType::GeneralContactExplicit)
            {
                isR &= readGeneralContactExplicit(interaction, stepID, stepGroup);
            }
            else if (InteractionType == Interface::FITKAbaAbstractInteraction::FITKAbaInteractionType::SurfToSurfContactExplicit)
            {
                isR &= readSurfToSurfExplicit(interaction, stepID, stepGroup);
            }
            else
            {
                return false;
            }
        }
        return isR;
    }

    bool FITKAbaqusHDF5AdaptorInteraction::readGeneralContactExplicit(Interface::FITKAbaAbstractInteraction* interaction, int stepID, H5::Group& h5Group)
    {
        auto generalContactExplicit = dynamic_cast<Interface::FITKAbaInteractionGeneralContactExplicit*>(interaction);
        if (!generalContactExplicit) return false;

        auto strIncludeSurfacePairs = readStrAttribute(h5Group, "IncludeSurfacePairs");
        Core::FITKEnumTransfer<Interface::GeneralContactExplicitData::IncludeSurfacePairs> fitkTypeTrafer;
        bool isValid = false;
        auto eIncludeSurfacePairs = fitkTypeTrafer.fromString(QString::fromStdString(strIncludeSurfacePairs), isValid);
        if (!isValid) return false;
        generalContactExplicit->setIncludeSurfacePairs(eIncludeSurfacePairs, stepID);
        int NumberOfIncludeSurfPairs = readIntAttribute(h5Group, "NumberOfIncludeSurfPairs");
        generalContactExplicit->setNumberOfIncludeSurfPairs(NumberOfIncludeSurfPairs, stepID);

        for (int i = 0; i < NumberOfIncludeSurfPairs; ++i)
        {
            auto IncludeSurfPairsGroup = h5Group.openGroup("IncludeSurfPairs");
            //$$$$ 
            if (!IncludeSurfPairsGroup.nameExists("first"))return false;
            if (!IncludeSurfPairsGroup.nameExists("second"))return false;
            auto firstGroup = IncludeSurfPairsGroup.openGroup("first");
            auto secondGroup = IncludeSurfPairsGroup.openGroup("second");

            int fModelID = readIntAttribute(firstGroup, "ModelID");
            int fComponentID = readIntAttribute(firstGroup, "ComponentID");

            int sModelID = readIntAttribute(secondGroup, "ModelID");
            int sComponentID = readIntAttribute(secondGroup, "ComponentID");

            auto IncludeSurfPair = generalContactExplicit->getIncludeSurfPair(i, stepID);
            auto first = IncludeSurfPair.first;
            auto second = IncludeSurfPair.second;
            first->setModel(fModelID);
            first->setComponent(fComponentID);
            second->setModel(sModelID);
            second->setComponent(sComponentID);
        }

        int ContactPropertyId = readIntAttribute(h5Group, "ContactPropertyId");
        generalContactExplicit->setContactPropertyId(ContactPropertyId);
        return true;
    }

    bool FITKAbaqusHDF5AdaptorInteraction::readSurfToSurfExplicit(Interface::FITKAbaAbstractInteraction* interaction, int stepID, H5::Group& h5Group)
    {
        auto surfToSurfExplicit = dynamic_cast<Interface::FITKAbaInteractionSurfToSurfExplicit*>(interaction);
        if (!surfToSurfExplicit) return false;
        bool isValid = false;

        auto MachanicalConstraintFormulation = readStrAttribute(h5Group, "MachanicalConstraintFormulation");
        Core::FITKEnumTransfer<Interface::FITKAbaInteractionSurfToSurfExplicit::MachanicalConstraintFormulation> fitkMTypeTrafer;
        auto eMachanicalConstraintFormulation = fitkMTypeTrafer.fromString(QString::fromStdString(MachanicalConstraintFormulation), isValid);
        if (!isValid) return false;
        surfToSurfExplicit->setMachanicalConstraintFormulation(eMachanicalConstraintFormulation);

        auto slidingFormulation = readStrAttribute(h5Group, "SlidingFormulation");
        Core::FITKEnumTransfer<Interface::FITKAbaAbstractInteraction::SlidingFormulation> fitkSTypeTrafer;
        auto eSlidingFormulation = fitkSTypeTrafer.fromString(QString::fromStdString(slidingFormulation), isValid);
        if (!isValid) return false;
        surfToSurfExplicit->setSlidingFormulation(eSlidingFormulation);

        auto initialClearance = readStrAttribute(h5Group, "InitialClearance");
        Core::FITKEnumTransfer<Interface::FITKAbaInteractionSurfToSurfExplicit::InitialClearance> fitkSsTypeTrafer;
        auto eInitialClearance = fitkSsTypeTrafer.fromString(QString::fromStdString(initialClearance), isValid);
        if (!isValid) return false;
        surfToSurfExplicit->setInitialClearance(eInitialClearance);

        double UniformClearance = readDoubleAttribute(h5Group, "UniformClearance");
        surfToSurfExplicit->setUniformClearance(UniformClearance);

        int ContactPropertyId = readIntAttribute(h5Group, "ContactPropertyId");
        surfToSurfExplicit->setContactPropertyId(ContactPropertyId);

        auto weightingFactor = readStrAttribute(h5Group, "WeightingFactor");
        Core::FITKEnumTransfer<Interface::FITKAbaInteractionSurfToSurfExplicit::WeightingFactor> fitkWTypeTrafer;
        auto eWeightingFactor = fitkWTypeTrafer.fromString(QString::fromStdString(weightingFactor), isValid);
        if (!isValid) return false;
        surfToSurfExplicit->setWeightingFactor(eWeightingFactor);

        double WeightingFactorValue = readDoubleAttribute(h5Group, "WeightingFactorValue");
        surfToSurfExplicit->setWeightingFactorValue(WeightingFactorValue);

        return true;
    }


    bool FITKAbaqusHDF5AdaptorInteraction::writeInteraction(Interface::FITKAbaAbstractInteraction * interaction, H5::Group & h5Group)
    {
        if (!interaction) return false;
        bool isW = true;
        bool isValid = false;

        std::string groupName = createParentAttribute(interaction, h5Group);
        if (groupName.empty())return false;

        auto interactionGroup = h5Group.createGroup(groupName);
        auto firstLocationGroup = interactionGroup.createGroup("FirstLocation");
        writeBoundaryLocation(interaction->getFirstLocation(), firstLocationGroup);
        auto secondLocationGroup = interactionGroup.createGroup("SecondLocation");
        writeBoundaryLocation(interaction->getSecondLocation(), secondLocationGroup);

        auto InteractionType = interaction->getInteractionType();
        //枚举转换字符
        Core::FITKEnumTransfer<Interface::FITKAbaAbstractInteraction::FITKAbaInteractionType> fitkITTypeTrafer;
        auto strInteractionType = fitkITTypeTrafer.toStrting(InteractionType, isValid);
        if (!isValid) return false;
        writeStrAttribute(interactionGroup, "Type", strInteractionType.toStdString());

        bool ActiveState = interaction->getActiveState();
        writeBoolAttribute(interactionGroup, "ActiveState", &ActiveState);
        auto stepManager = _caseData->getStepManager();
        if (!stepManager) return false;

        for (int i = 0; i < stepManager->getDataCount(); ++i)
        {
            auto step = stepManager->getDataByIndex(i);
            int stepID = step->getDataObjectID();
            auto stepGroup = interactionGroup.createGroup(std::to_string(stepID));

            //FITKAbaStepRelatedDataObject
            int CreatedStep = interaction->getCreatedStep();
            writeIntAttribute(stepGroup, "CreatedStep", &CreatedStep);
            int DeactiveStep = interaction->getDeactiveStep();
            writeIntAttribute(stepGroup, "DeactiveStep", &DeactiveStep);

            if (InteractionType == Interface::FITKAbaAbstractInteraction::FITKAbaInteractionType::GeneralContactExplicit)
            {
                isW &= writeGeneralContactExplicit(interaction, stepID, stepGroup);
            }
            else if (InteractionType == Interface::FITKAbaAbstractInteraction::FITKAbaInteractionType::SurfToSurfContactExplicit)
            {
                isW &= writeSurfToSurfExplicit(interaction, stepID, stepGroup);
            }
            else
            {
                return false;
            }
        }
        isW &= writeNDataObject(interaction, interactionGroup);

        return isW;
    }

    bool FITKAbaqusHDF5AdaptorInteraction::writeGeneralContactExplicit(Interface::FITKAbaAbstractInteraction* interaction, int stepID, H5::Group& h5Group)
    {
        auto generalContactExplicit = dynamic_cast<Interface::FITKAbaInteractionGeneralContactExplicit*>(interaction);
        if (!generalContactExplicit) return false;
        bool isValid = false;

        Core::FITKEnumTransfer<Interface::GeneralContactExplicitData::IncludeSurfacePairs> fitkISPTypeTrafer;
        QString sIncludeSurfacePairs = fitkISPTypeTrafer.toStrting(generalContactExplicit->getIncludeSurfacePairs(stepID), isValid);
        if (!isValid) return false;
        writeStrAttribute(h5Group, "IncludeSurfacePairs", sIncludeSurfacePairs.toStdString());

        int NumberOfIncludeSurfPairs = generalContactExplicit->getNumberOfIncludeSurfPairs(stepID);
        writeIntAttribute(h5Group, "NumberOfIncludeSurfPairs", &NumberOfIncludeSurfPairs);
        for (int i = 0; i < NumberOfIncludeSurfPairs; ++i)
        {
            auto IncludeSurfPairsGroup = h5Group.createGroup("IncludeSurfPairs");

            auto IncludeSurfPair = generalContactExplicit->getIncludeSurfPair(i, stepID);
            auto first = IncludeSurfPair.first;
            auto second = IncludeSurfPair.second;
            auto firstGroup = IncludeSurfPairsGroup.createGroup("first");
            auto secondGroup = IncludeSurfPairsGroup.createGroup("second");

            int fModelID = first->getModelID();
            writeIntAttribute(firstGroup, "ModelID", &fModelID);
            int fComponentID = first->getComponentID();
            writeIntAttribute(firstGroup, "ComponentID", &fComponentID);

            int sModelID = second->getModelID();
            writeIntAttribute(secondGroup, "ModelID", &sModelID);
            int sComponentID = second->getComponentID();
            writeIntAttribute(secondGroup, "ComponentID", &sComponentID);
        }

        int ContactPropertyId = generalContactExplicit->getContactPropertyId(stepID);
        writeIntAttribute(h5Group, "ContactPropertyId", &ContactPropertyId);
        return true;
    }

    bool FITKAbaqusHDF5AdaptorInteraction::writeSurfToSurfExplicit(Interface::FITKAbaAbstractInteraction* interaction, int stepID, H5::Group& h5Group)
    {
        auto surfToSurfExplicit = dynamic_cast<Interface::FITKAbaInteractionSurfToSurfExplicit*>(interaction);
        if (!surfToSurfExplicit) return false;
        bool isValid = false;

        //转换失败
        Core::FITKEnumTransfer<Interface::FITKAbaInteractionSurfToSurfExplicit::MachanicalConstraintFormulation> fitkMCFTypeTrafer;
        QString sMachanicalConstraintFormulation = fitkMCFTypeTrafer.toStrting(surfToSurfExplicit->getMachanicalConstraintFormulation(), isValid);
        if (!isValid) return false;
        writeStrAttribute(h5Group, "MachanicalConstraintFormulation", sMachanicalConstraintFormulation.toStdString());

        Core::FITKEnumTransfer<Interface::FITKAbaInteractionSurfToSurfExplicit::SlidingFormulation> fitkSFTypeTrafer;
        QString sSlidingFormulation = fitkSFTypeTrafer.toStrting(surfToSurfExplicit->getSlidingFormulation(), isValid);
        if (!isValid) return false;
        writeStrAttribute(h5Group, "SlidingFormulation", sSlidingFormulation.toStdString());

        Core::FITKEnumTransfer<Interface::FITKAbaInteractionSurfToSurfExplicit::InitialClearance> fitkICTypeTrafer;
        QString sInitialClearance = fitkICTypeTrafer.toStrting(surfToSurfExplicit->getInitialClearance(), isValid);
        if (!isValid) return false;
        writeStrAttribute(h5Group, "InitialClearance", sInitialClearance.toStdString());

        double UniformClearance = surfToSurfExplicit->getUniformClearance();
        writeDoubleAttribute(h5Group, "UniformClearance", &UniformClearance);
        int ContactPropertyId = surfToSurfExplicit->getContactPropertyId(stepID);
        writeIntAttribute(h5Group, "ContactPropertyId", &ContactPropertyId);

        Core::FITKEnumTransfer<Interface::FITKAbaInteractionSurfToSurfExplicit::WeightingFactor> fitkWTypeTrafer;
        QString sWeightingFactor = fitkWTypeTrafer.toStrting(surfToSurfExplicit->getWeightingFactor(), isValid);
        if (!isValid) return false;
        writeStrAttribute(h5Group, "WeightingFactor", sWeightingFactor.toStdString());

        double WeightingFactorValue = surfToSurfExplicit->getWeightingFactorValue();
        writeDoubleAttribute(h5Group, "WeightingFactorValue", &WeightingFactorValue);

        return true;
    }
}